package Tests
{
	import Box2D.Collision.Shapes.b2CircleShape;
	import Box2D.Collision.Shapes.b2EdgeShape;
	import Box2D.Collision.Shapes.b2PolygonShape;
	import Box2D.Collision.Shapes.b2Shape;
	import Box2D.Common.Math.b2Math;
	import Box2D.Common.Math.b2Transform;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Common.Math.b2Vec2Array;
	import Box2D.Dynamics.Joints.b2FrictionJointDef;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2BodyType;
	import Box2D.Dynamics.b2FixtureDef;
	
	import Framework.Test;

	public class ApplyForce extends Test 
	{
		private static const k_restitution:Number = .4;
		private var m_body:b2Body;
		private var ground:b2Body;
		public function ApplyForce()
		{
			super();
			m_world.SetGravity(new b2Vec2(0,0));
			
			var bodyDef:b2BodyDef = new b2BodyDef;
			bodyDef.position.Set(0,20);
			ground = m_world.CreateBody(bodyDef);
			var shape:b2EdgeShape = new b2EdgeShape;
			var fixtureDef:b2FixtureDef = new b2FixtureDef;
			fixtureDef.shape = shape;
			fixtureDef.density = 0;
			fixtureDef.restitution = k_restitution;
			
			// Left vertical
			shape.Set(new b2Vec2(-20,-20),new b2Vec2(-20,20));
			ground.CreateFixture(fixtureDef);
			// Right vertical
			shape.Set(new b2Vec2(20,-20),new b2Vec2(20,20));
			ground.CreateFixture(fixtureDef);
			// Top vertical
			shape.Set(new b2Vec2(-20,20),new b2Vec2(20,20));
			ground.CreateFixture(fixtureDef);
			// Buttom vertical
			shape.Set(new b2Vec2(-20,-20),new b2Vec2(20,-20));
			ground.CreateFixture(fixtureDef);
						
			createCrate()
			
			createJoints();
		}
		public override function get hotKeyNote():String{
			return '(a) rotate (d) rotate (w) applyForce'
		}
		private function createCrate():void{
			var xf1:b2Transform = new b2Transform;
			xf1.R.Set(0.3524*Math.PI);
			xf1.position = b2Math.MulA(xf1.R,new b2Vec2(1,0));
			var vertices:b2Vec2Array = new b2Vec2Array(3);
			vertices.setAt(0,b2Math.MulX(xf1,new b2Vec2(-1,0)));
			vertices.setAt(1,b2Math.MulX(xf1,new b2Vec2(1,0)));
			vertices.setAt(2,b2Math.MulX(xf1,new b2Vec2(0,.5)));
			var poly1:b2PolygonShape = new b2PolygonShape;
			poly1.Set(vertices,3);
			var sd1:b2FixtureDef = new b2FixtureDef;
			sd1.shape = poly1;
			sd1.density = 4;
			
			var xf2:b2Transform = new b2Transform;
			xf2.R.Set(-.3524*Math.PI);
			xf2.position = b2Math.MulA(xf2.R,new b2Vec2(-1,0));
			vertices.setAt(0,b2Math.MulX(xf2,new b2Vec2(-1,0)));
			vertices.setAt(1,b2Math.MulX(xf2,new b2Vec2(1,0)));
			vertices.setAt(2,b2Math.MulX(xf2,new b2Vec2(0,.5)));
			var poly2:b2PolygonShape = new b2PolygonShape;
			poly2.Set(vertices,3);
			var sd2:b2FixtureDef = new b2FixtureDef;
			sd2.shape = poly2;
			sd2.density = 2;
			
			var bd:b2BodyDef = new b2BodyDef;
			bd.type = b2BodyType.b2_dynamicBody;
			bd.angularDamping = 5;
			bd.linearDamping = .1;
			bd.position.Set(0,2);
			bd.angle = Math.PI;
			bd.allowSleep = false;
			
			m_body = m_world.CreateBody(bd);
			m_body.CreateFixture(sd1);
			m_body.CreateFixture(sd2)
		}
		private function createJoints():void{
			var shape:b2PolygonShape = new b2PolygonShape;
			shape.SetAsBox(.5,.5);
			var fd:b2FixtureDef = new b2FixtureDef;
			fd.shape = shape;
			fd.density = 1;
			fd.friction = .3;
			for(var i:int=0;i<10;++i){
				var bd:b2BodyDef = new b2BodyDef;
				bd.type = b2BodyType.b2_dynamicBody;
				bd.position.Set(0,5+1.54*i);
				var body:b2Body = m_world.CreateBody(bd);
				body.CreateFixture(fd);
				
				var gravity:Number = 10;
				var I:Number = body.GetInertia();
				var mass:Number = body.GetMass();
				
				var radius:Number = Math.sqrt(2*I/mass);
				
				var jd:b2FrictionJointDef = new b2FrictionJointDef;
				jd.localAnchorA.SetZero();
				jd.localAnchorB.SetZero();
				jd.bodyA = ground;
				jd.bodyB = body;
				jd.collideConnected = true;
				jd.maxForce = mass*gravity;
				jd.maxTorque = mass*radius*gravity;
				
				m_world.CreateJoint(jd);
			}
		}
		public override function Key(code:String):void
		{
			switch(code){
				case 'w':
					var f:b2Vec2 = m_body.GetWorldVector(new b2Vec2(0,-200));
					var p:b2Vec2 = m_body.GetWorldPoint(new b2Vec2(0,2));
					m_body.ApplyForce(f,p);
					break;
				case 'a':
					m_body.ApplyTorque(50);
					break;
				case 'd':
					m_body.ApplyTorque(-50);
					break;
			}
		}
	}
}